import pandas as pd
from abc import ABC, abstractmethod


from typing import Optional, Dict
import asyncio
from functools import lru_cache
from datetime import datetime

class DataFetcher(ABC):
    """数据获取器基类，支持缓存和并行获取"""
    
    def __init__(self):
        self._cache: Dict[str, pd.DataFrame] = {}
        self._max_retries = 3
        self._retry_delay = 1.0
    @lru_cache(maxsize=100)
    def fetch_data(self, symbol: str, start_date: str, end_date: str) -> pd.DataFrame:
        """获取市场数据，支持缓存和重试"""
        cache_key = f"{symbol}_{start_date}_{end_date}"
        if cache_key in self._cache:
            return self._cache[cache_key]
        
        for attempt in range(self._max_retries):
            try:
                data = self._fetch_data_impl(symbol, start_date, end_date)
                self._cache[cache_key] = data
                return data
            except Exception as e:
                if attempt == self._max_retries - 1:
                    raise
                import time
                time.sleep(self._retry_delay * (2 ** attempt))
        
        raise RuntimeError(f"Failed to fetch data after {self._max_retries} attempts")

    async def fetch_data_async(self, symbol: str, start_date: str, end_date: str) -> pd.DataFrame:
        """异步获取市场数据，支持缓存和重试"""
        cache_key = f"{symbol}_{start_date}_{end_date}"
        if cache_key in self._cache:
            return self._cache[cache_key]
        
        for attempt in range(self._max_retries):
            try:
                data = await asyncio.to_thread(self._fetch_data_impl, symbol, start_date, end_date)
                self._cache[cache_key] = data
                return data
            except Exception as e:
                if attempt == self._max_retries - 1:
                    raise
                await asyncio.sleep(self._retry_delay * (2 ** attempt))
        
        raise RuntimeError(f"Failed to fetch data after {self._max_retries} attempts")

    @abstractmethod
    def _fetch_data_impl(self, symbol: str, start_date: str, end_date: str) -> pd.DataFrame:
        """实际数据获取实现"""
        pass

    @abstractmethod
    def fetch_financials(self, symbol: str, report_type: str = 'annual') -> pd.DataFrame:
        """获取财务报表数据（年报/季报）
        Args:
            symbol: 股票代码
            report_type: 报告类型 (annual|quarterly)
        """

    async def fetch_multiple_data(self, symbols: list[str], start_date: str, end_date: str) -> Dict[str, pd.DataFrame]:
        """并行获取多个标的的数据"""
        tasks = []
        for symbol in symbols:
            task = asyncio.create_task(self._fetch_single_data(symbol, start_date, end_date))
            tasks.append(task)
        
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        data_dict = {}
        for symbol, result in zip(symbols, results):
            if not isinstance(result, Exception):
                data_dict[symbol] = result
        return {k: v for k, v in data_dict.items() if not isinstance(v, BaseException)}

    async def _fetch_single_data(self, symbol: str, start_date: str, end_date: str) -> pd.DataFrame:
        """异步获取单个标的的数据"""
        return await asyncio.to_thread(self.fetch_data, symbol, start_date, end_date)

    @abstractmethod
    def fetch_benchmark_data(self, benchmark_code: str, start_date: str, end_date: str) -> pd.DataFrame:
        """获取基准标的行情数据"""
        pass

    @abstractmethod
    def preprocess_data(self, raw_data: pd.DataFrame) -> pd.DataFrame:
        pass
